/**
 * @brief 演示pthread_specific的用法
 一个线程退出时，如果此前调用pthread_setspecific建立了key<->data的关联且data != nullptr，key destructor != nullptr，则会调用destructor(data)
 如果pthread_key_create时没有指定destructor，则不会调用
 如果没有调用pthread_setspecific，则不会调用destructor
 如果调用pthread_setspecific(key, nullptr)，则也不会调用destructor
 如果先调用pthread_setspecific(key, data)，但是在线程退出前又调用了pthread_setspecific(key, nullptr)，那么线程退出后也不会调用destructor
 */


#include<thread>
#include<pthread.h>
#include<sys/prctl.h>
#include<random>
#include<iostream>

int g_value = 100;
struct
{
	int a;
	int b;
	int c;
}g_tvalue = {123, 456, 789};

void f1(pthread_key_t key)
{
	std::random_device rd;
	prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("sub_f1"), 0, 0, 0);
	pthread_setspecific(key, &g_value);
	std::this_thread::sleep_for(std::chrono::seconds(rd() % 5 + 1));
}

void f2(pthread_key_t key)
{
	std::random_device rd;
	prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("sub_f2"), 0, 0, 0);
	pthread_setspecific(key, &g_value);
	std::this_thread::sleep_for(std::chrono::seconds(rd() % 5 + 1));
}

void f3(pthread_key_t key)
{
	std::random_device rd;
	prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("sub_f3"), 0, 0, 0);
	pthread_setspecific(key, &g_tvalue);
	std::this_thread::sleep_for(std::chrono::seconds(rd() % 5 + 1));
}

void delete_key_fun(void* data)
{
	char name[16] {0};
	prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(name));
	
	std::cout<< name << " thread data is " << data << std::endl;
	if (nullptr != data)
	{
		std::cout<< "value: " << *static_cast<int*>(data) << std::endl;
	}
}

int main(void)
{
	pthread_key_t key;
	pthread_key_create(&key, delete_key_fun);
	
	std::thread t1(f1, key);
	std::thread t2(f2, key);
	std::thread t3(f3, key);
	
	t1.join();
	t2.join();
	t3.join();
	
	pthread_key_delete(key);
}
